﻿// Decompiled with JetBrains decompiler
// Type: Microsoft.InfoCards.CryptoSession
// Assembly: infocard, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// MVID: 8E14765A-6610-409A-BA36-099A0642905D
// Assembly location: E:\git\ALLIDA\windll\infocard.exe

using Microsoft.InfoCards.Diagnostics;
using System;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography;
using System.Security.Principal;
using System.Threading;

namespace Microsoft.InfoCards
{
  internal abstract class CryptoSession
  {
    public static readonly TimeSpan MaxSessionLifetime = new TimeSpan(1, 0, 0);
    private static CryptoSession.CryptoSessionDictionary s_sessionCollection = new CryptoSession.CryptoSessionDictionary();
    private static object s_syncRoot = new object();
    private const int m_MaxSessionCount = 1073741823;
    private Process m_process;
    private int m_sessionid;
    private EventHandler m_processExitHandler;
    private EventHandler m_serviceStoppingHandler;
    private Timer m_timer;
    private bool m_isDisposed;
    private object m_syncRoot;
    private WindowsIdentity m_identity;
    private DateTime m_expiration;
    private CryptoSession.SessionType m_type;

    protected CryptoSession(
      Process process,
      DateTime expiration,
      WindowsIdentity identity,
      object key,
      CryptoSession.SessionType type)
    {
      InfoCardTrace.Assert(null != key, "null key passed in to CryptoSession ctor");
      try
      {
        this.m_process = ProcessMonitor.GetProcessById(process.Id);
      }
      catch (ArgumentException ex)
      {
        throw InfoCardTrace.ThrowHelperError((Exception) new ProcessExitedException(SR.GetString("ServiceClientProcessExited", (object) process.Id), (Exception) ex));
      }
      this.m_syncRoot = new object();
      this.m_identity = identity;
      this.m_expiration = expiration;
      this.m_type = type;
      lock (CryptoSession.s_syncRoot)
      {
        int newHandle;
        try
        {
          newHandle = CryptoSession.s_sessionCollection.GetNewHandle();
        }
        catch (IndexOutOfRangeException ex)
        {
          throw InfoCardTrace.ThrowHelperError((Exception) new ServiceBusyException(SR.GetString("ServiceTooManyCryptoSessions", (object) CryptoSession.s_sessionCollection.MaxSize), (Exception) ex));
        }
        bool flag = false;
        try
        {
          this.m_processExitHandler = new EventHandler(this.OnProcessExit);
          this.m_process.Exited += this.m_processExitHandler;
          if (process.HasExited || this.m_process.HasExited)
            throw InfoCardTrace.ThrowHelperError((Exception) new ProcessExitedException(SR.GetString("ServiceProcessHasExited")));
          TimeSpan dueTime = expiration - DateTime.UtcNow;
          if (dueTime > CryptoSession.MaxSessionLifetime)
            dueTime = CryptoSession.MaxSessionLifetime;
          this.m_timer = new Timer(InfoCardTrace.ThunkCallback(new TimerCallback(this.OnTimeout)), (object) null, dueTime, new TimeSpan(0, 0, 0, 0, -1));
          this.m_serviceStoppingHandler = new EventHandler(this.OnServiceStopping);
          InfoCardService.Stopping += this.m_serviceStoppingHandler;
          CryptoSession.s_sessionCollection[newHandle] = this;
          this.m_sessionid = newHandle;
          flag = true;
        }
        finally
        {
          if (!flag)
            CryptoSession.s_sessionCollection.Remove(newHandle);
        }
      }
    }

    protected uint ProcessId
    {
      get
      {
        return (uint) this.m_process.Id;
      }
    }

    protected Process ProcessObj
    {
      get
      {
        return this.m_process;
      }
    }

    protected WindowsIdentity Identity
    {
      get
      {
        return this.m_identity;
      }
    }

    protected SecurityIdentifier ClientSid
    {
      get
      {
        return this.m_identity.User;
      }
    }

    protected DateTime Expiration
    {
      get
      {
        return this.m_expiration;
      }
    }

    public void Write(BinaryWriter bwriter)
    {
      bwriter.Write((int) this.m_type);
      bwriter.Write(this.m_sessionid);
      bwriter.Write(this.m_expiration.ToFileTime());
      this.OnWrite(bwriter);
    }

    private void OnTimeout(object state)
    {
      this.Dispose();
    }

    private void OnProcessExit(object sender, EventArgs e)
    {
      this.DisposeAsClient();
    }

    private void OnServiceStopping(object sender, EventArgs e)
    {
      this.DisposeAsClient();
    }

    private void DisposeAsClient()
    {
      try
      {
        WindowsImpersonationContext impersonationContext = this.m_identity.Impersonate();
        try
        {
          this.Dispose();
        }
        finally
        {
          impersonationContext.Undo();
        }
      }
      catch (Exception ex)
      {
        throw;
      }
    }

    protected void ThrowIfDisposed()
    {
      if (this.m_isDisposed)
        throw InfoCardTrace.ThrowHelperError((Exception) new ObjectDisposedException("CryptoSession " + (object) this.m_sessionid));
    }

    protected virtual void OnDispose()
    {
    }

    protected virtual void OnWrite(BinaryWriter bwriter)
    {
    }

    public void Dispose()
    {
      bool flag = false;
      lock (this.m_syncRoot)
      {
        if (!this.m_isDisposed)
        {
          this.m_isDisposed = true;
          flag = true;
          if (this.m_serviceStoppingHandler != null)
          {
            InfoCardService.Stopping -= this.m_serviceStoppingHandler;
            this.m_serviceStoppingHandler = (EventHandler) null;
          }
          if (this.m_process != null)
          {
            if (this.m_processExitHandler != null)
            {
              this.m_process.Exited -= this.m_processExitHandler;
              this.m_processExitHandler = (EventHandler) null;
            }
            this.m_process = (Process) null;
          }
          if (this.m_timer != null)
          {
            this.m_timer.Dispose();
            this.m_timer = (Timer) null;
          }
          this.OnDispose();
        }
      }
      if (!flag)
        return;
      lock (CryptoSession.s_syncRoot)
        CryptoSession.s_sessionCollection.Remove(this.m_sessionid);
    }

    public static CryptoSession Create(
      Process process,
      DateTime expiration,
      WindowsIdentity identity,
      RSACryptoServiceProvider key)
    {
      return (CryptoSession) new AsymmetricCryptoSession(process, expiration, identity, key);
    }

    public static CryptoSession Create(
      Process process,
      DateTime expiration,
      WindowsIdentity identity,
      byte[] key)
    {
      return (CryptoSession) new SymmetricCryptoSession(process, expiration, identity, key);
    }

    public static CryptoSession Find(
      int sessionId,
      uint processId,
      SecurityIdentifier clientSid)
    {
      CryptoSession session;
      lock (CryptoSession.s_syncRoot)
      {
        if (!CryptoSession.s_sessionCollection.ContainsHandle(sessionId))
          throw InfoCardTrace.ThrowHelperError((Exception) new CommunicationException(SR.GetString("ServiceUnknownCryptoSessionId")));
        session = CryptoSession.s_sessionCollection[sessionId];
        if ((int) session.ProcessId != (int) processId)
          throw InfoCardTrace.ThrowHelperError((Exception) new CommunicationException(SR.GetString("ServiceUnknownCryptoSessionId")));
        if (session.ClientSid != clientSid)
          throw InfoCardTrace.ThrowHelperError((Exception) new CommunicationException(SR.GetString("ServiceUnknownCryptoSessionId")));
      }
      return session;
    }

    private class CryptoSessionDictionary : HandleDictionary<CryptoSession>
    {
    }

    protected enum SessionType
    {
      Asymmetric = 1,
      Symmetric = 2,
      Transfrom = 3,
      Hash = 4,
    }
  }
}
